package com.oplink.webems.common.snmp.service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.oplink.webems.common.config.Global;
import com.oplink.webems.common.snmp.base.SnmpException;
import com.oplink.webems.modules.alarm.dao.AlarmSeverDao;
import com.oplink.webems.modules.alarm.dao.AlarmTypeDao;
import com.oplink.webems.modules.alarm.entity.AlarmCurrent;
import com.oplink.webems.modules.alarm.service.AlarmCurrentService;
import com.oplink.webems.modules.cfg.entity.CfgNe;
import com.oplink.webems.modules.cfg.services.CfgNeService;
import com.oplink.webems.modules.event.entity.BaseEvent;
import com.oplink.webems.modules.event.service.EventCenter;

@Component
@Transactional
public class NodePoll implements Runnable {

	@Autowired
	CfgNeService cns;
	
	@Autowired
	private EventCenter ec;
	
	@Autowired
	private AlarmCurrentService acs;
	
	@Autowired
	AlarmTypeDao alarmTypeDao;
	
	@Autowired
	AlarmSeverDao alarmseverDao ;
	
	public static boolean hasNewNode = false;
	
	ExecutorService exe = Executors.newFixedThreadPool(20);
	@Override
	@Transactional(propagation=Propagation.NOT_SUPPORTED)
	public void run() {
		while(MainServer.servletRun){
			try {
				Thread.sleep(Integer.parseInt(Global.getConfig("nodePollTimeInterval")));
			} catch (NumberFormatException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			boolean _a = hasNewNode;
			pollNode(_a);
			hasNewNode = false;
		}
		
	}
	
	/**
	 * 是否是初始化的检测工作
	 * @param init
	 */
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	public void pollNode(boolean init){
		// get neList
		List<CfgNe> list = cns.getAllNe();
		// define future list
		List<Future<Boolean>> fList = new ArrayList<Future<Boolean>>();
		
		//final boolean  _init = init;
		// fill 'future list' with the function what get ne offlineStatus 
		for(CfgNe _ne : list){
			//在Callable内部会调用ne的acurList，所以里将该属性lazyload后，再传入Callable
			//并且一定要加Transction注解，lazyload才会作用，不然会报错
			_ne.getAcurlist().size();
			final CfgNe ne = _ne;
			
			Future<Boolean> f = exe.submit(new Callable<Boolean>() {

				@Override
				public Boolean call() throws Exception {
					SnmpService ss = new SnmpService(ne.getIp(), "Admin@123");
					boolean active = ss.active();
					ss.closeSession();
					
					return active;
				}
			});
			
			fList.add(f);
		}
		
		// check if functions in thread pool are completed, if no the 'f.get()' will throws exception
		List<Boolean> retList = new ArrayList<Boolean>();
		for(Future<Boolean> f : fList){
			try {
				retList.add(f.get());
			} catch (InterruptedException e) {
				e.printStackTrace();
				return;
			} catch (ExecutionException e) {
				e.printStackTrace();
				return;
			}
		}
		for(int i=0; i<list.size(); i++){
			CfgNe ne = list.get(i);
			boolean active = retList.get(i);
			if(init){
				updateAlarms(ne, active);
			}else{
				if( (CfgNe.STATUS_OFFLINE.equals(ne.getOffline()) && active) ||
						(CfgNe.STATUS_ONLINE.equals(ne.getOffline()) && !active)){
					ne.setOffline(active?CfgNe.STATUS_ONLINE:CfgNe.STATUS_OFFLINE);
					cns.save(ne);
					updateAlarms(ne, active);
				}
			}
		}
	}
	
	/**
	 * 刷新告警让数据库与NE同步
	 * @param ne
	 */
	private void updateAlarms(CfgNe ne , boolean active){
		
			List<AlarmCurrent> listEquip ;
			if(active){
				try {
					//在线就取设备上的告警
					listEquip = acs.getAlarm(ne);
				} catch (SnmpException e) {
					e.printStackTrace();
					return;
				}
			}else{
				//不在线就生成一个离线告警
				listEquip = new ArrayList<AlarmCurrent>();
				AlarmCurrent a = new AlarmCurrent();
				a.setAid(CfgNe.OFFLINE_ALARMNAME);
				a.setAtype(alarmTypeDao.findOne(2L));
				a.setSlot(null);
				a.setChassis(1);
				a.setPort(-1);
				a.setNenode(ne);
				
				a.setSeverity(alarmseverDao.findOne((long)CfgNe.OFFLINE_ALARMSERVERITY));
				
				listEquip.add(a);
			}
			
			List<AlarmCurrent> listDb = ne.getAcurlist();
			//printAlarmIds(ne.getIp(),listDb);
			List<AlarmCurrent> listEquipLeft = new ArrayList<AlarmCurrent>();
			//List<AlarmCurrent> listDbLeft = new ArrayList<AlarmCurrent>();
			
			for(AlarmCurrent aEquip : listEquip){
				boolean found = false;
				for(AlarmCurrent aDb : listDb){
					if(aEquip.getCompositeKey().equals(aDb.getCompositeKey())){
						listDb.remove(aDb);
						found = true;
						break;
					}
				}
				if(!found){
					listEquipLeft.add(aEquip);
				}
			}
			
			
			/*for(AlarmCurrent a : listDbLeft){
				listDb.remove(a);
				acs.delCurRow(new String[]{String.valueOf(a.getId())});
				
				toEventCenter(false, a);
			}*/
			for(int i = listDb.size()-1; i>-1; i--){
				AlarmCurrent a = listDb.get(i);
				//将告警从当前告警中删除
				listDb.remove(a);
				acs.delCurRow1(new String[]{String.valueOf(a.getId())});
				
				toEventCenter(false, a);
			}
			for(AlarmCurrent a : listEquipLeft){
				//将告警保存到数据库
				if(a.getId()!=null){
					a.setId(null);
				}
				AlarmCurrent _a = acs.save(a);
				
				toEventCenter(true, _a);
			}
					
	}
	

	public void toEventCenter(boolean add, AlarmCurrent a){
		//如果这里不将缓存要加载的属性添加上，后面进行json转换的时候会报Exception
		if(a.getSlot() !=null && a.getSlot().getCard()!=null){
			a.getSlot().getCard().getSlot();
		}else{
			a.setSlot(null);
		}
		
		BaseEvent be = new BaseEvent();
		
		be.setType(BaseEvent.TYPE_ALARM_NE);
		be.setAction(add?BaseEvent.ACTION_VALUE_ON:BaseEvent.ACTION_VALUE_OFF);
		be.setEntity(a);
		
		ec.put(be);
	}
	
	
	/*private void printAlarmIds(String ip,List<AlarmCurrent> l) {
		System.out.print("ip :"+ip+":");
		for(AlarmCurrent a : l){
			System.out.print(a.getId()+",");
		}
		System.out.println();
	}*/
}
